package com.xbongbong.saas.model.impl;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.pojo.dto.InsertDTO;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.RelTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.dao.ProductStockDao;
import com.xbongbong.saas.domain.entity.ProductStockEntity;
import com.xbongbong.saas.domain.entity.ProductStockUpdateEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.subform.ProductStockSubFormEnum;
import com.xbongbong.saas.model.ProductStockModel;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.join.query.HasParentQueryBuilder;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author haibin.zhang
 * @version v1.0
 * @date 2019/6/7 14:16
 * @since v1.0
 */
@Service
public class ProductStockModelImpl implements ProductStockModel {
    private static final Logger LOG = LoggerFactory.getLogger(ProductStockModelImpl.class);

    @Resource
    private ProductStockDao productStockDao;
    @Resource
    private EsHelper esHelper;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;

    @Override
    public Integer insert(ProductStockEntity entity) throws XbbException {
        return null;
    }

    @Override
    public Integer update(ProductStockEntity entity) throws XbbException {
        return null;
    }

    @Override
    public List<ProductStockEntity> findEntitys(Map<String, Object> param) {
        return productStockDao.findEntitys(param);
    }

    @Override
    public void updateBatch(List<ProductStockEntity> updateList,String corpid) throws XbbException {
        productStockDao.updateBatch(updateList,corpid);
        List<PaasFormDataEntity> paasFormDataEntities = transferSubFormHelper.transferProductStockToFormDataList(updateList);

        List<InsertDTO> updateDTOList = new ArrayList<>();
        for (PaasFormDataEntity paasFormDataEntity : paasFormDataEntities) {
            updateDTOList.add(paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO));
        }

//        for (ProductStockEntity entity : updateList){
//            InsertDTO insertDTO = new InsertDTO();
//            insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
//            insertDTO.setEsId(entity.getCorpid() + "_" + entity.getId());
//            insertDTO.setParent(entity.getCorpid() + "_" + entity.getProductId());
//            insertDTO.setSource(BeanUtil.convertBean2Map(entity,false,true));
//            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO);
//            updateDTOList.add(insertDTO);
//        }
        paasEsModel.updateBatch(updateDTOList);
    }

    @Override
    public void insertBatch(List<ProductStockEntity> insertList) throws XbbException {
//        for (ProductStockEntity productStockEntity : insertList) {
//            if (StringUtil.isEmpty(productStockEntity.getBatchKey())){
//                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,"productBatch 唯一标识丢失");
//            }
//        }
        if (insertList.size() == 1){
            productStockDao.insert(insertList.get(0));
        }else {
            productStockDao.insertBatch(insertList);
        }

        List<PaasFormDataEntity> paasFormDataEntities = transferSubFormHelper.transferProductStockToFormDataList(insertList);
        List<InsertDTO> insertDTOList = new ArrayList<>();
        for (PaasFormDataEntity paasFormDataEntity : paasFormDataEntities) {
            insertDTOList.add(paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO));
        }

//        for (ProductStockEntity productStockEntity : insertList){
//            InsertDTO insertDTO = new InsertDTO();
//            insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
//            insertDTO.setEsId(productStockEntity.getCorpid() + "_" + productStockEntity.getId());
//            insertDTO.setParent(productStockEntity.getCorpid() + "_" + productStockEntity.getProductId());
//            insertDTO.setSource(BeanUtil.convertBean2Map(productStockEntity, false, true));
//            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO);
//            insertDTOList.add(insertDTO);
//        }
        if (insertList.size() == 1){
            paasEsModel.insert(insertDTOList.get(0));
        }else {
            paasEsModel.insertBatch(insertDTOList, WriteRequest.RefreshPolicy.NONE);
        }
    }

    @Override
    public List<ProductStockEntity> getValidBatchInfoList(List<Long> pageProductIds, String corpid, Long warehouseId, String batch, List<String> fieldList) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery(ProductStockSubFormEnum.getEsAttr(ProductStockSubFormEnum.PRODUCT_ID),pageProductIds));
        boolQueryBuilder.filter(termQuery(ProductStockSubFormEnum.getEsAttr(ProductStockSubFormEnum.WAREHOUSE_CHECKED),1));
        if (!Objects.isNull(warehouseId)){
            boolQueryBuilder.filter(termQuery(ProductStockSubFormEnum.getEsAttr(ProductStockSubFormEnum.WAREHOUSE_ID),warehouseId));
        }
        if (!Objects.isNull(batch)){
            boolQueryBuilder.filter(termQuery(ProductStockSubFormEnum.getEsAttr(ProductStockSubFormEnum.BATCH),batch));
        }
        List<PaasFormDataEntity> list = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO,boolQueryBuilder,PaasFormDataEntity.class,fieldList);
        return transferSubFormHelper.transferFormDataToProductStockList(list);
    }

    @Override
    public void dataConsistencyUpdateWarehouse(String corpid, Long dataId, String name) {
        try {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("warehouseId", dataId);
            param.put("del", 0);
            List<ProductStockEntity> productStockEntityList = findEntitys(param);
            for (ProductStockEntity entity : productStockEntityList) {
                entity.setWarehouseName(name);
            }
            if (Objects.nonNull(productStockEntityList) && !productStockEntityList.isEmpty()) {
                updateBatchWarehouse(productStockEntityList, corpid);
            }
        } catch (Exception e) {
            LOG.error("ProductStockModelImpl.dataConsistencyUpdateWarehouse 出错， corpid=" + corpid + "  warehouseId=" + dataId + "  warehouseName=" + name, e);
        }
    }

    /**
     * 批量更新仓库名称
     *
     * @param updateList
     * @param corpid
     * @throws XbbException
     */
    @Override
    public void updateBatchWarehouse(List<ProductStockEntity> updateList,String corpid) throws XbbException {
        productStockDao.updateBatchWarehouse(updateList, corpid);
        List<PaasFormDataEntity> paasFormDataEntities = transferSubFormHelper.transferProductStockToFormDataList(updateList);

        List<InsertDTO> updateDTOList = new ArrayList<>();
        for (PaasFormDataEntity paasFormDataEntity : paasFormDataEntities) {
            updateDTOList.add(paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO));
        }

//        for (ProductStockEntity entity : updateList){
//            InsertDTO insertDTO = new InsertDTO();
//            insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
//            insertDTO.setEsId(entity.getCorpid() + "_" + entity.getId());
//            insertDTO.setParent(entity.getCorpid() + "_" + entity.getProductId());
//            insertDTO.setSource(BeanUtil.convertBean2Map(entity,false,true));
//            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO);
//            updateDTOList.add(insertDTO);
//        }
        paasEsModel.updateBatch(updateDTOList, WriteRequest.RefreshPolicy.NONE);
    }

    @Override
    public void deleteByIdIn(String corpid, List<ProductStockEntity> productStockEntityList) throws XbbException {
        if (productStockEntityList.isEmpty()){
            return;
        }
        List<Long> idIn = new ArrayList<>();
        List<InsertDTO> updateDTOList = new ArrayList<>();
        Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        map.put(StringConstant.DEL, DelEnum.DELETE.getDel());
        map.put(StringConstant.UPDATE_TIME, DateTimeUtil.getInt());
        productStockEntityList.forEach(item -> {
            idIn.add(item.getId());
            InsertDTO insertDTO = new InsertDTO();
            insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
            insertDTO.setEsId(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO.getType() + "_" + corpid + "_" + item.getId());
            insertDTO.setParent(corpid + "_" + item.getProductId());
            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO);
            insertDTO.setSource(map);
            updateDTOList.add(insertDTO);
        });
        productStockDao.deleteByIdIn(corpid, idIn);
        paasEsModel.updateBatch(updateDTOList);
    }


    @Override
    public List<ProductStockEntity> findEntitysForUpdate(Map<String, Object> map) {
        return productStockDao.findEntitysForUpdate(map);
    }

    @Override
    public void updateStockDB(Set<String> batchKeyList, Collection<ProductStockUpdateEntity> values, String corpid) throws XbbException {
        if (batchKeyList.isEmpty()) {
            return;
        }
        productStockDao.updateStockDB(batchKeyList,values,corpid);
        Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.CORPID,corpid);
        param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
        param.put("batchKeyIn",batchKeyList);
        List<ProductStockEntity> productStockEntityList = findEntitysForUpdate(param);
        if (productStockEntityList.isEmpty()){
            return;
        }
        List<InsertDTO> updateBatchList = new ArrayList<>();
        for (ProductStockEntity entity : productStockEntityList) {
            Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            JSONObject object = new JSONObject();
            object.put(ProductStockSubFormEnum.NUM.getDataAttr(),entity.getNum());
            object.put(ProductStockSubFormEnum.COST.getDataAttr(),entity.getCost());
            object.put(ProductStockSubFormEnum.TOTAL_COST.getDataAttr(), entity.getTotalCost());
            map.put(StringConstant.JSON_DATA, object);
            InsertDTO insertDTO = new InsertDTO();
            insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
            insertDTO.setEsId(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO.getType() + "_" + entity.getCorpid() + "_" + entity.getId());
            insertDTO.setParent(entity.getCorpid() + "_" + entity.getProductId());
            insertDTO.setSource(map);
            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO);
            updateBatchList.add(insertDTO);
        }
        paasEsModel.updateBatch(updateBatchList, WriteRequest.RefreshPolicy.NONE);
    }

    @Override
    public List<String> getExistBatchKeyList(String corpid, Set<String> batchKeyList) {
        if(CollectionsUtil.isEmpty(batchKeyList)) {
            return new ArrayList<>();
        }
        return productStockDao.getExistBatchKeyList(corpid,batchKeyList);
    }

    @Override
    public List<ProductStockEntity> getExistBatchEntity(String corpid, Set<Long> parentIdIn) {
        return productStockDao.getExistBatchEntity(corpid, parentIdIn);
    }

    @Override
    public List<ProductStockEntity> getHasBatchStockList(Map<String, Object> map) {
        return productStockDao.getHasBatchStockList(map);
    }

    @Override
    public List<String> getCorpidExistBatch(List<String> corpidList) {
        return productStockDao.getCorpidExistBatch(corpidList);
    }

    @Override
    public void updateStockBatch(List<ProductStockEntity> updateProductStockList, String corpid) throws XbbException {
        productStockDao.updateStockBatch(updateProductStockList,corpid);
        List<InsertDTO> updateBatchList = new ArrayList<>();
        for (ProductStockEntity entity : updateProductStockList) {
            Map<String,Object> map = new HashMap<>(2);
            map.put(ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.NUM),entity.getNum());
            InsertDTO insertDTO = new InsertDTO();
            insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
            insertDTO.setEsId(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO.getType() + "_" + entity.getCorpid() + "_" + entity.getId());
            insertDTO.setParent(entity.getCorpid() + "_" + entity.getProductId());
            insertDTO.setSource(map);
            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO);
            updateBatchList.add(insertDTO);
        }
        paasEsModel.updateBatch(updateBatchList, WriteRequest.RefreshPolicy.NONE);
    }

    @Override
    public Integer getEntitysCount(Map<String, Object> param){
        return productStockDao.getEntitysCount(param);
    }

    @Override
    public List findEntitysWithoutSub(Map<String, Object> param) {
        return null;
    }

    @Override
    public List<String> getLatestDistinctBatch(String corpid, String batch) {
        return productStockDao.getLatestDistinctBatch(corpid, batch);
    }

    @Override
    public List<PaasFormDataEntity> getWithInExpirationDateList(String corpid, String symbol, List<Object> timeRange) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder parentBoolQueryBuilder = boolQuery();
        parentBoolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        parentBoolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        parentBoolQueryBuilder.mustNot(termQuery(ProductEnum.getEsAttr4Keyword(ProductEnum.PARENT_ID), 0));
        parentBoolQueryBuilder.filter(termQuery(ProductEnum.getEsAttr4Keyword(ProductEnum.ENABLE_BATCH_SHELF_LIFE), 1));
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        List<ConditionsEntityExt> productSearchList = new ArrayList<>();
        ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt(ProductStockSubFormEnum.EXPIRE_DATE.getDataAttr(), "", symbol, timeRange, FieldTypeEnum.BATCH_PRODUCE_DATE.getType());
        productSearchList.add(conditionsEntityExt);
        EsUtil.parseProductSearchCondition(boolQueryBuilder, productSearchList, RelTypeEnum.AND.getAlias(), corpid, XbbRefTypeEnum.GUARANTEE_SEARCH.getCode());
        HasParentQueryBuilder hasParentQueryBuilder = JoinQueryBuilders.hasParentQuery(IndexTypeEnum.IDX_SAAS_PRODUCT.getType(), parentBoolQueryBuilder, false);

        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(hasParentQueryBuilder);
        IndexTypeEnum indexTypeEnum = EsHelper.getIndexTypeEnum(SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.PRODUCT_STOCK_INFO.getCode());
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        EsUtil.setFieldList(sourceBuilder, Arrays.asList(ProductStockSubFormEnum.PRODUCT_ID.getDataAttr()));
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(searchRequest, PaasFormDataEntity.class);
        if (esEntities == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return esEntities.getContent();
    }

    /**
     * 根据产品ID和仓库ID查询仓库产品信息
     *
     * @param corpid        公司ID
     * @param productIdIn   产品ID
     * @param warehouseIdIn 仓库ID
     * @return 仓库产品信息
     */
    @Override
    public List<ProductStockEntity> listByProductIdInAndWarehouseIdIn(String corpid, List<Long> productIdIn, List<Long> warehouseIdIn, List<String> batchLsit) throws XbbException {
        Map<String, Object> param = new HashMap<>(4);
        param.put("del", 0);
        param.put("corpid", corpid);
        param.put("productIdIn", productIdIn);
        param.put("warehouseIdIn", warehouseIdIn);
        param.put("batchIn", batchLsit);
        return this.findEntitys(param);
    }

    /**
     * 根据产品ID和仓库ID查询仓库产品信息
     *
     * @param corpid      公司ID
     * @param productIdIn 产品ID
     * @return 仓库产品信息
     */
    @Override
    public List<ProductStockEntity> listByProductIdIn(String corpid, List<Long> productIdIn, List<Long> warehouseIdIn) {
        Map<String, Object> param = new HashMap<>(3);
        param.put("del", 0);
        param.put("corpid", corpid);
        param.put("productIdIn", productIdIn);
        param.put("warehouseIdIn", warehouseIdIn);
        return this.findEntitys(param);
    }

    @Override
    public void updateProductStockById(List<ProductStockEntity> productStockEntityList, String corpid){
        productStockDao.updateProductStockById(productStockEntityList, corpid);
    }

    @Override
    public List<ProductStockEntity> getCostIsNullBatchKey(String corpid, List<Long> productIdList){
        return productStockDao.getCostIsNullBatchKey(corpid, productIdList);
    }
}
